#include <QSqlDatabase>
#include <QSqlQuery>
#include<QSqlError>
#include <QTime>
#include <QSqlRecord>
#include <QtDebug>
#include "DbConnection.h"

DbConnection::DbConnection(const Parameters &params):logiN(0)
{
    prm.DbName=params.DbName;
    prm.driver=params.driver;
    prm.host=params.host;
    prm.port=params.port;
    prm.schema=params.schema;

    db = QSqlDatabase::addDatabase(params.driver, QString::number(long(this)));
    db.setHostName(params.host);
    db.setDatabaseName(params.DbName);
    db.setPort(params.port);
}

DbConnection::DbConnection():logiN(0){}

bool DbConnection::login(const QString &name,const  QString &pass)
{
    if((name.isEmpty())||(pass.isEmpty())) return 0;
    db.setUserName(name);
    db.setPassword(pass);
    prm.user=name;
    prm.password=pass;
    logiN=db.open();
    return logiN;
}

DbConnection::~DbConnection()
{
    closeDb();
}

void DbConnection::closeDb()
{
    db.close();
    logiN=0;
}

QString DbConnection::errorMessage()
{
    return db.lastError().text();
}

bool DbConnection::isDbOpen()
{
    if(db.isOpen())
        {
            QSqlQuery q(db);
            if(q.exec("select 1"))
            {
                return true;
            }
            else
            {
                qWarning() << tr("Db: database connection lost: ") << q.lastError().text();
                db.close();
                return false;
            }
        }
        if(!db.open())
        {
            qDebug() << db.lastError().text();
            return false;
        }
        qDebug() << tr("Db: connection to database repaired.");
        return false;
}

DbConnection::QueryResult DbConnection::execute(const QString& sql)
{    
    if(isDbOpen())
    {
        QSqlQuery q(db);
        emit status(1);
        emit busy(1);
        QString query=sql;
        if(q.exec(query.replace("=schema=",prm.schema)))
        {
            QVector < QVector < QVariant> > tmp;
            while(q.next())
            {
                    QVector < QVariant > row;
                    for(int i = 0; i < q.record().count(); i++)
                        row.push_back(q.value(i));
                    tmp.push_back(row);
            }
            QStringList fields;
            for(int i=0;i<q.record().count();i++)
                fields.append(q.record().fieldName(i));
            emit status(0);
            emit results(QueryResult(tmp, fields, q.numRowsAffected()));
            emit busy(0);
            return QueryResult(tmp, fields, q.numRowsAffected());
        }
        else
        {
            qWarning() << "query: " << sql;
            qWarning() << q.lastError().text();
            emit results(QueryResult(q.lastError().text()));
            emit busy(0);
            emit status(-1);
            return QueryResult(q.lastError().text());
        }
    }
    else
    {
        emit status(-1);
        return QueryResult(db.lastError().text());
    }
}

DbConnection::QueryResult::QueryResult()
                    :ok(true),mes(tr("No errors")){}

DbConnection::QueryResult::QueryResult(const QVector<QVector<QVariant> > &result)
                    :res(result), ok(true),mes(tr("No errors")){}

DbConnection::QueryResult::QueryResult(const QString &errorMessage)
                    :res(QVector < QVector < QVariant> >()), ok(false),mes(errorMessage){}

DbConnection::QueryResult::QueryResult(const QVector<QVector<QVariant> > &result,
                                       const QStringList &fields,const int&RAF)
                    :res(result), ok(true),mes(tr("No errors")),FieldsName(fields), rAf(RAF){}


bool DbConnection::QueryResult::success() const
{
    return ok;
}

int DbConnection::QueryResult::rows() const
{
    return res.count();
}

int DbConnection::QueryResult::rowsAffected() const
{
    return rAf;
}

int DbConnection::QueryResult::columns() const
{
    return ((res.count() > 0) ? (res.at(0).count()) : (0));
}

QVariant DbConnection::QueryResult::at(const int& row, const int& col) const
{
    if(row < 0 || row >= rows() || col < 0 || col >= columns())
        return QVariant();

    return res.at(row).at(col);
}

QString DbConnection::QueryResult::errorMessage() const
{
    return mes;
}

QString  DbConnection::QueryResult::fieldName(const int&index) const
{
    if((index>=0)&&(index<FieldsName.count()))
        return FieldsName.at(index);
    else
        return "";
}

QString DbConnection::host()
{
    return prm.host;
}

QString DbConnection::dbName()
{
    return prm.DbName;
}

int DbConnection::port()
{
    return prm.port;
}

QString DbConnection::user()
{
    return prm.user;
}

QString DbConnection::driver() const
{
    return prm.driver;
}

QString DbConnection::password()
{
    return prm.password;
}

void DbConnection::setParameters(const DbConnection::Parameters &params)
{
    prm.host=params.host;
    prm.DbName=params.DbName;
    prm.port=params.port;
    prm.user=params.user;
    prm.driver=params.driver;
    prm.password=params.password;

    QString lastName=db.connectionName();
    db = QSqlDatabase();
    QSqlDatabase::removeDatabase(lastName);
    db = QSqlDatabase::addDatabase(params.driver, QString::number(long(this)));
    db.setHostName(params.host);
    db.setDatabaseName(params.DbName);
    db.setPort(params.port);
}

void DbConnection::setParametersAndLogin(const DbConnection::Parameters &params)
{
    setParameters(params);
    login(params.user, params.password);
    QString name=tr("Текущее соединение: %1@%2:%3");
    name=name.arg(prm.user).arg(prm.DbName).arg(prm.host);
    emit changeConnectionName(name);
}

QSqlError DbConnection::lastError() const
{
    return db.lastError();
}
